package org.example;

import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import java.util.Scanner;

/**
 * Netty 核心组件关系
 * Bootstrap/ServerBootstrap
 *     ├── EventLoopGroup (boss/worker) 事件循环组，包含多个EventLoop(事件循环，处理I/O事件和任务)
 *     ├── Channel (NioSocketChannel/NioServerSocketChannel) 网络连接通道
 *     └── ChannelPipeline 处理器链, chanelHandler(业务处理器) 处理I/O事件和任务
 *         ├── ChannelHandlerContext 上下文对象
 *         ├── ChannelInboundHandler 输入处理器
 *         └── ChannelOutboundHandler 输出处理器
 */
public class NettyClient {
    public static void main(String[] args) throws InterruptedException {
        /*
         * 客户端只需要一个EventLoopGroup
         * 用于处理所有I/O操作
         */
        EventLoopGroup group = new NioEventLoopGroup();

        try {
            /*
             * 创建Bootstrap实例
             * 配置客户端参数
             */
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) {
                            /*
                             * 添加自定义处理器到管道
                             * 与服务端保持一致的编解码器
                             */
                            ChannelPipeline pipeline = ch.pipeline();
                            pipeline.addLast(new StringDecoder());
                            pipeline.addLast(new StringEncoder());
                            pipeline.addLast(new ClientHandler());
                        }
                    });

            /*
             * 连接服务端
             * sync()方法会阻塞直到连接完成
             */
            ChannelFuture future = bootstrap.connect("localhost", 8080).sync();
            Channel channel = future.channel();

            /*
             * 从控制台读取输入并发送到服务端
             * 这里使用Scanner读取用户输入
             */
            Scanner scanner = new Scanner(System.in);
            while (scanner.hasNextLine()) {
                String line = scanner.nextLine();
                channel.writeAndFlush(line + "\n");
            }

            /*
             * 等待连接关闭
             */
            channel.closeFuture().sync();
        } finally {
            /*
             * 优雅关闭EventLoopGroup
             */
            group.shutdownGracefully();
        }
    }
}